package com.zhangkunhao.notes.util;

import java.io.FileInputStream;

import java.sql.*;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;

/**
 * 连接池，使用单例模式
 *
 * @author 张坤浩
 */
public class MyDataSource {
    private static String driverClassName = null;
    private static String url = null;
    private static String user = null;
    private static String password = null;

    private static final int INIT_COUNT = 5;
    private static final int MAX_COUNT = 10;
    private int currentCount = 0;

    // 注册驱动
    static {
        //创建配置文件对象
        Properties p = new Properties();
        try {
            //加载src下的配置文件信息，注意每次都要改相对路径,同时在main和Junit框架中运行时使用的相对路径不一样
            p.load(new FileInputStream("demo01/src/jdbc.properties"));
            driverClassName = p.getProperty("driverClassName");
            url = p.getProperty("url");
            user = p.getProperty("user");
            password = p.getProperty("password");
            // 注册驱动
            Class.forName(driverClassName);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 声明连接池变量，由于操作连接池主要是增加，删除操作，LinkedList比ArrayList增删快，所以这里选用LinkedList
     */
    private final LinkedList<Connection> pools = new LinkedList<>();

    /**
     * 创建对象时，连接池中就有5个连接了
     *
     * @throws SQLException
     */
    private MyDataSource() throws SQLException {
        for (int i = 0; i < INIT_COUNT; i++) {
            Connection conn = this.createConnection();
            // 这里添加的时候添加到第一个，后面获取的时候，获取最后一个
            pools.addFirst(conn);
            this.currentCount++;
        }
    }

    /**
     * 创建连接池对象
     */
    private static MyDataSource myDataSource;

    static {
        try {
            myDataSource = new MyDataSource();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单例模式，通过静态方法获得数据池对象
     *
     * @return
     */
    public static MyDataSource getInstance() {
        return myDataSource;
    }

    public Connection getConnection() throws SQLException {
        //返回连接方式2：
        synchronized (pools) {
            if (this.pools.size() > 0) {
                // 获取的时候，获取最后一个连接
                return this.pools.removeLast();
            }
            if (this.currentCount < MAX_COUNT) {
                this.currentCount++;
                System.out.println("连接池已经提供：" + this.currentCount);
                return this.createConnection();
            }
            throw new SQLException("已没有连接");
        }
    }

    public Connection createConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }

    /**
     * 关闭资源，注意关闭从下往上关
     *
     * @param conn
     * @param ps
     */
    public void free(Connection conn, PreparedStatement ps, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //回收连接
        if (conn != null) {
            this.pools.addFirst(conn);
        }
    }
}